package com.hiv.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.hiv.common.NaiYaoRequest;
import com.hiv.common.PageInfo;
import com.hiv.common.enums.AccountTypeEnum;
import com.hiv.common.enums.ErrorCode;
import com.hiv.common.exception.BusinessException;
import com.hiv.common.helper.AccountHelper;
import com.hiv.common.param.InspectionStatisticsParam;
import com.hiv.common.param.page.PageQuerySamplingRecordParam;
import com.hiv.common.response.InspectionStatisticsInfo;
import com.hiv.common.response.StorageStatisticsInfo;
import com.hiv.common.utils.AssertUtil;
import com.hiv.mapper.*;
import com.hiv.mapper.domain.*;
import com.hiv.model.DiseaseResult;
import com.hiv.utils.FileUploadUtils;
import com.hiv.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采样数据Service业务层处理
 *
 * @author zhanghong
 * @date 2022-09-20
 */
@Slf4j
@Service
public class SamplingRecordService {

    private static final String URL = "https://tools.yishushow.com/hiv/translate_report";

    /**
     *
     */
    private static final String SAMPLE_ID = "SAMPLE ID";
    /**
     * 病载检测结果值key
     */
    private static final String RESULT = "RESULT";

    @Autowired
    private SamplingRecordMapper samplingRecordMapper;
    @Autowired
    private PatientService patientService;
    @Autowired
    private HospitalService hospitalService;
    @Autowired
    private HospitalMapper hospitalMapper;
    @Autowired
    private AdminAccountService adminAccountService;
    @Autowired
    private BatchMapper batchMapper;
    @Autowired
    private BarCodeMapper barCodeMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private AccountHelper accountHelper;
    @Autowired
    private SamplingRecordResultMapper samplingRecordResultMapper;
    @Autowired
    private UserService userService;
    @Autowired
    private ReportCodeMapper reportCodeMapper;
    @Autowired
    private InspectionOfficeConfigMapper inspectionOfficeConfigMapper;
    @Autowired
    private SamplingBoxMapper samplingBoxMapper;

    /**
     * 分页查询
     *
     * @param param
     * @return
     */
    public PageInfo<SamplingRecord> pageQuery(Admin admin, PageQuerySamplingRecordParam param) {
        if (AccountTypeEnum.isQualityControlCenterAdmin(admin)) {
            //质控中心-则查询质控中心下所有医院的采样数据
            List<Long> hospitalIdList = accountHelper.qualityControlCenterRelationHospitalIdList(admin.getHospitalId());
            if (CollectionUtils.isEmpty(hospitalIdList)) {
                return new PageInfo<>(param.getPageNum(), param.getPageSize(), Lists.newArrayList(), 0);
            }
            param.setHospitalId(null);
            param.setInspectionId(null);
            param.setHospitalIdList(hospitalIdList);
        } else if (AccountTypeEnum.isInspectionAdmin(admin)) {
            param.setHospitalIdList(accountHelper.inspectionRelationHospitalIdList(admin.getHospitalId()));
            param.setHospitalId(null);
        } else if (admin != null && admin.getType() == null) {//库管员/检验员
            Integer countRole = roleMapper.countKgOrJyyByAdminId(admin.getId());
            AssertUtil.assertNotEqual(countRole, 0, "仅库管员/检验员操作");
            param.setHospitalIdList(accountHelper.inspectionRelationHospitalIdList(admin.getHospitalId()));
            param.setHospitalId(null);
        }

        if (Objects.equals(param.getSampleStatus(), 5)) {//前端搜索【待检测】的所有数据
            param.getSampleStatusList().clear();
        } else if (Objects.equals(param.getSampleStatus(), 6)) {//前端搜索【已完成】的所有数据
            param.setSampleStatus(null);
            param.getSampleStatusList().clear();
            param.setReportStatus(2);
        } else if (Objects.equals(param.getSampleStatus(), 7)) {//前端搜索【检测中】的所有数据
            param.setSampleStatus(null);
            param.getSampleStatusList().clear();
            param.setSampleStatusList(Lists.newArrayList(6, 7));
            param.setReportStatus(1);
        }

        long count = samplingRecordMapper.pageCount(param);
        List<SamplingRecord> list = samplingRecordMapper.pageQuery(param, param.getPageSize(), param.fetchOffSet());
        list.stream().forEach(item -> buildInfo(item));
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), list, count);
    }

    /**
     * 分页查询
     *
     * @param param
     * @return
     */
    public PageInfo<SamplingRecord> forDoctorPageQuery(PageQuerySamplingRecordParam param) {
        long count = samplingRecordMapper.forDoctorPageCount(param);
        List<SamplingRecord> list = samplingRecordMapper.forDoctorPageQuery(param, param.getPageSize(), param.fetchOffSet());
        list.stream().forEach(item -> buildInfo(item));
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), list, count);
    }

    /**
     * 联合分页查询
     *
     * @param param
     * @return
     */
    public PageInfo<SamplingRecord> unionPageQuery(PageQuerySamplingRecordParam param) {
        long count = samplingRecordMapper.pageCount(param);
        List<SamplingRecord> list = samplingRecordMapper.pageQuery(param, param.getPageSize(), param.fetchOffSet());
        //todo 改成多线程
        list.stream().forEach(item -> buildInfo(item));
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), list, count);
    }

    /**
     * 组装信息
     *
     * @param item
     */
    private void buildInfo(SamplingRecord item) {
        item.setHospitalName(hospitalService.getHospitalName(item.getHospitalId()));
        item.setSamplerName(adminAccountService.getUserName(item.getSamplerId()));
        item.setStoragerName(adminAccountService.getUserName(item.getStoragerId()));
        item.setInspectorName(adminAccountService.getUserName(item.getInspectorId()));
        //填充委托单位
        item.setBaseEntrustUnit(hospitalService.getHospitalName(item.getHospitalId()));

        Batch batch = batchMapper.queryBySamplingRecord(item.getId());
        if (batch != null) {
            item.setBatchCode(batch.getCode());
            item.setExpress(batch.getExpress());
        }

        //查询检验结果信息
        List<SamplingRecordResult> resultList = samplingRecordResultMapper.listBySamplingId(item.getId());
        if (CollectionUtils.isNotEmpty(resultList)) {
            if (item.getCheckType() == 1) {
                SamplingRecordResult recordResult = resultList.get(0);
                item.setDiseaseResult(recordResult.getDiseaseResult());
                item.setDiseaseNum(0);
                try {
                    String[] copies = recordResult.getDiseaseResult().split("Copies");
                    if (copies != null && copies.length > 0) {
                        item.setDiseaseNum(Integer.parseInt(StringUtils.trim(copies[0]).replaceAll(",", "")));
                    }
                } catch (Exception ex) {
                    log.error("转换病载含量数据异常");
                }
            } else if (item.getCheckType() == 2) {
                List<SamplingRecordResult> newResult = Lists.newArrayList();
                List<com.alibaba.fastjson.JSONObject> resultsList = Lists.newArrayList();
                List<SamplingRecordResult> recordResults = resultList.stream().filter(obj -> Objects.equals(obj.getType(), 1)).collect(Collectors.toList());
                Map<String, List<SamplingRecordResult>> map = recordResults.stream().filter(data -> data.getDiseaseResult() == null).collect(Collectors.groupingBy(SamplingRecordResult::getDrugCategory));
                map.forEach((key, value) -> {
                    com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
                    jsonObject.put("name", key);
                    jsonObject.put("list", value);
                    newResult.addAll(value);
                    resultsList.add(jsonObject);
                });
                item.setDrugResultList(resultsList);

                map.forEach((key, value) -> {
                    SamplingRecordResult recordResult = value.get(0);
                    int i = newResult.indexOf(recordResult);
                    newResult.get(i).setRowSpan(value.size());
                });
                // newResult 原数组
                List<SamplingRecordResult> drugResultSourceList = newResult.stream().filter(item1->Objects.equals(item1.getType(), 1)).collect(Collectors.toList());
                List<SamplingRecordResult> drugResultPointList = resultList.stream().filter(item1->Objects.equals(item1.getType(), 2)).collect(Collectors.toList());
                //【耐药】
                item.setDrugResultSourceList(drugResultSourceList);
                //【耐药位点】
                item.setDrugResultPointList(drugResultPointList);

            } else if (item.getCheckType() == 3) {
                Optional<SamplingRecordResult> first = resultList.stream().filter(data -> data.getDiseaseResult() != null).findFirst();
                if (first.isPresent()) {
                    item.setDiseaseResult(first.get().getDiseaseResult());
                    item.setDiseaseNum(0);
                    try {
                        String[] copies = first.get().getDiseaseResult().split("Copies");
                        if (copies != null && copies.length > 0) {
                            item.setDiseaseNum(Integer.parseInt(StringUtils.trim(copies[0]).replaceAll(",", "")));
                        }
                    } catch (Exception ex) {
                        log.error("转换病载含量数据异常");
                    }
                }

                List<SamplingRecordResult> newResult = Lists.newArrayList();
                List<com.alibaba.fastjson.JSONObject> resultsList = Lists.newArrayList();
                List<SamplingRecordResult> recordResults = resultList.stream().filter(obj -> Objects.equals(obj.getType(), 1)).collect(Collectors.toList());
                Map<String, List<SamplingRecordResult>> map = recordResults.stream().filter(data -> data.getDiseaseResult() == null).collect(Collectors.groupingBy(SamplingRecordResult::getDrugCategory));
                map.forEach((key, value) -> {
                    com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
                    jsonObject.put("name", key);
                    jsonObject.put("list", value);
                    newResult.addAll(value);
                    resultsList.add(jsonObject);
                });
                item.setDrugResultList(resultsList);

                map.forEach((key, value) -> {
                    SamplingRecordResult recordResult = value.get(0);
                    int i = newResult.indexOf(recordResult);
                    newResult.get(i).setRowSpan(value.size());
                });
                // newResult 原数组

                List<SamplingRecordResult> drugResultSourceList = newResult.stream().filter(item1->Objects.equals(item1.getType(), 1)).collect(Collectors.toList());
                List<SamplingRecordResult> drugResultPointList = resultList.stream().filter(item1->Objects.equals(item1.getType(), 2)).collect(Collectors.toList());
                //【耐药】
                item.setDrugResultSourceList(drugResultSourceList);
                //【耐药位点】
                item.setDrugResultPointList(drugResultPointList);
            }
        }

        //编制人
        if (item.getCompleteUser() != null) {
            item.setCompleteUserSign(userService.getSignById(item.getCompleteUser()));
        }
        //审核人
        if (item.getAuditUser() != null) {
            item.setAuditUserSign(userService.getSignById(item.getAuditUser()));
        }
        //批准人
        if (item.getRatifyUser() != null) {
            item.setRatifyUserSign(userService.getSignById(item.getRatifyUser()));
        }

        //填充检验所配置信息
        InspectionOfficeConfig inspectionOfficeConfig = inspectionOfficeConfigMapper.selectByHospitalId(item.getInspectionId());
        if (inspectionOfficeConfig != null) {
            item.setBaseInspectionUnit(Optional.ofNullable(item.getBaseInspectionUnit()).orElse(inspectionOfficeConfig.getBaseInspectionUnit()));
            item.setBaseUnitAddress(Optional.ofNullable(item.getBaseUnitAddress()).orElse(inspectionOfficeConfig.getBaseUnitAddress()));
            item.setBaseUnitEmail(Optional.ofNullable(item.getBaseUnitEmail()).orElse(inspectionOfficeConfig.getBaseUnitEmail()));
            item.setBaseUnitPhone(Optional.ofNullable(item.getBaseUnitPhone()).orElse(inspectionOfficeConfig.getBaseUnitPhone()));
            item.setReportInfo(Optional.ofNullable(item.getReportInfo()).orElse(inspectionOfficeConfig.getReportInfo()));
            item.setStorageTemperature(Optional.ofNullable(item.getStorageTemperature()).orElse(inspectionOfficeConfig.getStorageTemperature()));
            item.setReceiveTemperature(Optional.ofNullable(item.getReceiveTemperature()).orElse(inspectionOfficeConfig.getReceiveTemperature()));
            item.setSymbolDiseaseInspectBasis(Optional.ofNullable(item.getSymbolDiseaseInspectBasis()).orElse(inspectionOfficeConfig.getSymbolDiseaseInspectBasis()));
            item.setSymbolDrugInspectBasis(Optional.ofNullable(item.getSymbolDrugInspectBasis()).orElse(inspectionOfficeConfig.getSymbolDrugInspectBasis()));
            item.setSymbolDiseaseInspectDevice(Optional.ofNullable(item.getSymbolDiseaseInspectDevice()).orElse(inspectionOfficeConfig.getSymbolDiseaseInspectDevice()));
            item.setSymbolDrugInspectDevice(Optional.ofNullable(item.getSymbolDrugInspectDevice()).orElse(inspectionOfficeConfig.getSymbolDrugInspectDevice()));
            item.setSymbolInspectResult(Optional.ofNullable(item.getSymbolInspectResult()).orElse(inspectionOfficeConfig.getSymbolInspectResult()));
            item.setSymbolRemark(Optional.ofNullable(item.getSymbolRemark()).orElse(inspectionOfficeConfig.getSymbolRemark()));
            item.setLastRemark(Optional.ofNullable(item.getLastRemark()).orElse(inspectionOfficeConfig.getLastRemark()));

            item.setLogo(inspectionOfficeConfig.getLogo());
            item.setElectronicSeal(inspectionOfficeConfig.getElectronicSeal());
        }

    }

    /**
     * 查询采样数据
     *
     * @param id 采样数据主键
     * @return 采样数据
     */
    public SamplingRecord getById(Long id) {
        SamplingRecord samplingRecord = samplingRecordMapper.selectById(id);
        buildInfo(samplingRecord);
        return samplingRecord;
    }

    /**
     * 查询采样数据列表
     *
     * @param samplingRecord 采样数据
     * @return 采样数据
     */
    public List<SamplingRecord> selectList(SamplingRecord samplingRecord) {
        List<SamplingRecord> list = samplingRecordMapper.selectList(samplingRecord);
        list.stream().forEach(item -> buildInfo(item));
        return list;
    }

    /**
     * 保存采样数据
     *
     * @param samplingRecord 采样数据
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean save(SamplingRecord samplingRecord) {
        if (samplingRecord.getId() != null) {
            samplingRecordMapper.update(samplingRecord);
            return true;
        }

        //条码校验
        BarCode barCode = barCodeMapper.queryByCode(samplingRecord.getBarCode());
        AssertUtil.assertNotNull(barCode, "条码不存在");
        AssertUtil.assertTrue(barCode.getStatus() == 2, "条码未出库");
        SamplingRecord db = samplingRecordMapper.queryByBarCode(samplingRecord.getBarCode());
        AssertUtil.assertNull(db, "已存在采样记录");

        int insert = samplingRecordMapper.insert(samplingRecord);
        if (insert == 1) {
            //新增患者记录
            Patient patient = new Patient();
            patient.setAntiviralCode(samplingRecord.getAntiviralCode());
            patient.setCheckType(samplingRecord.getCheckType());
            patient.setSamplingId(samplingRecord.getId());
            patient.setHospitalId(samplingRecord.getHospitalId());
            patientService.save(patient);
        }
        return true;
    }

    /**
     * 提交采样数据
     *
     * @param admin
     * @param samplingRecord 采样数据
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean inspection(Admin admin, SamplingRecord samplingRecord) {
        //校验
        SamplingRecord record = samplingRecordMapper.selectById(samplingRecord.getId());
        AssertUtil.assertNotNull(record, "数据不存在");
        //校验是否是当前检验所下的采样数据
        AssertUtil.assertTrue(Objects.equals(admin.getHospitalId(), record.getInspectionId()), "非当前检验所数据，请检查");
        AssertUtil.assertFalse(record.getSampleStatus() == 5, "已提交检测");
        AssertUtil.assertTrue(Objects.equals(record.getSampleStatus(), 1), "状态异常：入库正常的数据才能提交检测");
        if (samplingRecord.getId() != null) {
            samplingRecordMapper.update(samplingRecord);
            return true;
        }
        return true;
    }

    /**
     * 批量删除采样数据
     *
     * @param ids 需要删除的采样数据主键
     * @return 结果
     */
    public Boolean deleteByIds(String ids) {
        samplingRecordMapper.deleteByIds(Convert.toStrArray(ids));
        return true;
    }

    /**
     * 重新采集
     *
     * @param ids
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean resampling(List<Long> ids) {
        for (Long id : ids) {
            SamplingRecord samplingRecord = samplingRecordMapper.selectById(id);
            samplingRecord.setResamplingStatus(1);
            samplingRecordMapper.update(samplingRecord);
        }
        return true;
    }

    /**
     * 根据barCode查询
     *
     * @param barCode
     * @return
     */
    public SamplingRecord getByBarCode(String barCode) {
        SamplingRecord samplingRecord = samplingRecordMapper.queryByBarCode(barCode);
        if (samplingRecord != null) {
            buildInfo(samplingRecord);
        }
        return samplingRecord;
    }

    /**
     * 入库统计
     *
     * @param admin
     * @return
     */
    public StorageStatisticsInfo storageStatistics(Admin admin) {
        StorageStatisticsInfo statisticsInfo = new StorageStatisticsInfo();
        Integer todayStorage = samplingRecordMapper.inspectionTodayStorageCount(admin.getHospitalId());
        Integer todayException = samplingRecordMapper.inspectionTodayExceptionCount(admin.getHospitalId());
        Double failRate = 0d;
        if (todayStorage != 0) {
            BigDecimal result = NumberUtil.round(NumberUtil.div(todayException, todayStorage), 4);
            failRate = result.doubleValue();
        }
        Integer totalStorage = samplingRecordMapper.inspectionTotalStorageCount(admin.getHospitalId());

        statisticsInfo.setTodayStorage(todayStorage);
        statisticsInfo.setFailRate(failRate);
        statisticsInfo.setTotalStorage(totalStorage);
        return statisticsInfo;
    }

    /**
     * 检测统计
     *
     * @param admin
     * @return
     */
    public InspectionStatisticsInfo inspectionStatistics(Admin admin) {
        Long inspectionId = null;
        InspectionStatisticsInfo info = new InspectionStatisticsInfo();
        if (admin.getType() == null) {
            //查询当前是否是检验所下的检验员
            Hospital hospital = hospitalMapper.selectById(admin.getHospitalId());
            if (hospital.getType() == 3) {
                admin.setType(3);
                inspectionId = admin.getHospitalId();
            }
        }

        InspectionStatisticsParam param = new InspectionStatisticsParam();
        if (admin.getType() == 1) {//质控中心
            List<Hospital> hospitals = hospitalMapper.listByParentId(admin.getHospitalId());
            param.setHospitalId(null);
            List<Long> yiYuanIds = hospitals.stream().map(Hospital::getId).collect(Collectors.toList());
            param.setHospitalIdList(yiYuanIds);
        }
        if (admin.getType() == 2) {//医院
            param.setHospitalId(admin.getHospitalId());
        }
        if (admin.getType() == 3) {//检验所
            param.setInspectionId(admin.getHospitalId());
            inspectionId = admin.getHospitalId();
        }
        Integer todayFinish = samplingRecordMapper.inspectionTodayFinishCount(param);
        Integer inspection = samplingRecordMapper.inspectionCount(param);

        if (inspectionId != null) {
            Set<Long> hospitalIdList = samplingBoxMapper.queryByInspectionId(inspectionId);
            hospitalIdList.stream().collect(Collectors.toList());
            param.setHospitalIdList(Lists.newArrayList(hospitalIdList));
        }


        Integer totalFinish = samplingRecordMapper.inspectionTotalFinishCount(param);
        info.setTodayFinish(todayFinish);
        info.setInspection(inspection);
        info.setTotalFinish(totalFinish);
        return info;
    }

    /**
     * 采样入库
     *
     * @param param
     * @return
     */
    public Boolean updateStatus(Admin admin, SamplingRecord param) {
        //入库校验
        AssertUtil.assertNotNull(param.getId(), "id不能为空");
        SamplingRecord db = samplingRecordMapper.selectById(param.getId());
        AssertUtil.assertNotNull(db, "采样数据不存在");
        //校验是否是当前检验所的数据
        SamplingBox samplingBox = samplingBoxMapper.queryBySamplingRecordId(db.getId());
        AssertUtil.assertNotNull(samplingBox, "寄样盒子不存在");
        AssertUtil.assertTrue(Objects.equals(samplingBox.getInspectionId(), admin.getHospitalId()), "条码与检验所不匹配");
        if (samplingBox.getExpressStatus() != 3) {
            //将盒子快递状态变更为已收件
            samplingBoxMapper.updateExpressStatus(samplingBox.getId(), 3);
        }


        //入库
        samplingRecordMapper.update(param);
        return true;
    }

    /**
     * 报告完善提交
     *
     * @param param
     * @return
     */
    public Boolean completeSampleInfo(Admin admin, SamplingRecord param) {
        //入库校验
        AssertUtil.assertNotNull(param.getId(), "id不能为空");
        SamplingRecord db = samplingRecordMapper.selectById(param.getId());
        AssertUtil.assertNotNull(db, "采样数据不存在");

        //完善报告信息
        param.setCompleteStatus(2);
        param.setCompleteUser(admin.getId());
        param.setAuditStatus(1);
        samplingRecordMapper.update(param);
        return true;
    }

    /**
     * 报告完善列表
     *
     * @param admin
     * @param param
     * @return
     */
    public PageInfo<SamplingRecord> authorizedStrengthPageQuery(Admin admin, PageQuerySamplingRecordParam param) {
        param.setSampleStatus(6);
        long count = samplingRecordMapper.pageCount(param);
        List<SamplingRecord> list = samplingRecordMapper.pageQuery(param, param.getPageSize(), param.fetchOffSet());
        list.stream().forEach(item -> buildInfo(item));
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), list, count);
    }

    /**
     * 报告审核列表
     *
     * @param admin
     * @param param
     * @return
     */
    public PageInfo<SamplingRecord> auditPageQuery(Admin admin, PageQuerySamplingRecordParam param) {
        param.setSampleStatus(6);//已完成
        param.setCompleteStatus(2);//已完善
        param.setAuditStatusList(Lists.newArrayList(1, 2));//待审核 or 通过
        long count = samplingRecordMapper.pageCount(param);
        List<SamplingRecord> list = samplingRecordMapper.pageQuery(param, param.getPageSize(), param.fetchOffSet());
        list.stream().forEach(item -> buildInfo(item));
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), list, count);
    }

    /**
     * 报告审核列表-通过
     *
     * @param admin
     * @param id
     * @return
     */
    public Boolean auditPass(Admin admin, long id) {
        AssertUtil.assertNotNull(id, "id不能为空");
        SamplingRecord db = samplingRecordMapper.selectById(id);
        AssertUtil.assertNotNull(db, "采样数据不存在");
        db.setAuditStatus(2);
        db.setAuditUser(admin.getId());
        db.setRatifyStatus(1);
        db.setReportStatus(1);
        samplingRecordMapper.update(db);
        return true;
    }

    /**
     * 报告审核列表-驳回
     *
     * @param admin
     * @param id
     * @return
     */
    public Boolean auditReject(Admin admin, long id) {
        AssertUtil.assertNotNull(id, "id不能为空");
        SamplingRecord db = samplingRecordMapper.selectById(id);
        AssertUtil.assertNotNull(db, "采样数据不存在");
        db.setAuditStatus(3);
        db.setAuditUser(admin.getId());
        samplingRecordMapper.update(db);
        return true;
    }

    /**
     * 报告批准列表
     *
     * @param admin
     * @param param
     * @return
     */
    public PageInfo<SamplingRecord> ratifyPageQuery(Admin admin, PageQuerySamplingRecordParam param) {
        param.setSampleStatus(6);//已完成
        param.setCompleteStatus(2);//已提交
        param.setAuditStatus(2);//审核通过
        param.setRatifyStatusList(Lists.newArrayList(1, 2));//待批准 or 已通过
        long count = samplingRecordMapper.pageCount(param);
        List<SamplingRecord> list = samplingRecordMapper.pageQuery(param, param.getPageSize(), param.fetchOffSet());
        list.stream().forEach(item -> buildInfo(item));
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), list, count);
    }

    /**
     * 报告批准列表-通过
     *
     * @param admin
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized SamplingRecord ratifyPass(Admin admin, long id) {
        AssertUtil.assertNotNull(id, "id不能为空");
        SamplingRecord db = samplingRecordMapper.selectById(id);
        AssertUtil.assertNotNull(db, "采样数据不存在");
        db.setRatifyStatus(2);
        db.setRatifyUser(admin.getId());
        db.setRatifyTime(new Date());
        db.setReportStatus(2);
        //生成编号
        db.setDiseaseReportCode(getDiseaseReportCode(db.getCheckType()));
        db.setDrugReportCode(getDrugReportCode(db.getCheckType()));
        db.setFinishTime(new Date());
        samplingRecordMapper.update(db);
        SamplingRecord record = samplingRecordMapper.selectById(id);
        buildInfo(record);
        return record;
    }

    /**
     * 获取病载编号
     *
     * @param checkType
     * @return
     */
    private String getDiseaseReportCode(Integer checkType) {
        if (checkType == 1 || checkType == 3) {
            ReportCode reportCode = reportCodeMapper.queryDiseaseReportCode();
            AssertUtil.assertNotNull(reportCode, "病载报告编码不存在");

            Integer current = Optional.ofNullable(reportCode.getCurrent()).orElse(0);
            reportCodeMapper.update(reportCode.getId(), current + 1);
            return String.format("VL%06d", current + 1);
        }
        return null;
    }

    /**
     * 获取耐药编号
     *
     * @param checkType
     * @return
     */
    private String getDrugReportCode(Integer checkType) {
        if (checkType == 2 || checkType == 3) {
            ReportCode reportCode = reportCodeMapper.queryDrugReportCode();
            AssertUtil.assertNotNull(reportCode, "耐药报告编码不存在");

            Integer current = Optional.ofNullable(reportCode.getCurrent()).orElse(0);
            reportCodeMapper.update(reportCode.getId(), current + 1);
            return String.format("VS%06d", current + 1);
        }
        return null;
    }

    /**
     * 报告批准列表-驳回
     *
     * @param admin
     * @param id
     * @return
     */
    public Boolean ratifyReject(Admin admin, long id) {
        AssertUtil.assertNotNull(id, "id不能为空");
        SamplingRecord db = samplingRecordMapper.selectById(id);
        AssertUtil.assertNotNull(db, "采样数据不存在");
        db.setCompleteStatus(1);
        db.setAuditStatus(3);
        db.setRatifyUser(admin.getId());
        samplingRecordMapper.update(db);
        return true;
    }

    /**
     * 上传病载检验结果excel
     *
     * @param file
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean uploadExcelAndResolving(MultipartFile file, Long id, Long inspectionId) {
        try {
            //解析病载检验结果数据
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<List<Object>> results = reader.read();
            //校验
            long count = results.stream().filter(item -> item.size() > 1).filter(item -> Objects.equals(item.get(1), SAMPLE_ID)).count();
            AssertUtil.assertTrue(count == 1, "导入数据有错误，请检查，验证必填项信息是否存在，验证为一项是否存在");

            //获取病载检验数据
            Boolean filterFlag = true;
            List<DiseaseResult> excelResult = Lists.newArrayList();
            for (List<Object> result : results) {
                if (filterFlag) {
                    if (result.size() < 2 || !Objects.equals(result.get(1), SAMPLE_ID)) {
                        continue;
                    } else {
                        filterFlag = false;
                        continue;
                    }
                }

                //写入检验结果数据
                if (result.size() < 5) {
                    continue;
                }
                excelResult.add(DiseaseResult.builder().barCode(result.get(1).toString()).result(result.get(5).toString()).build());
            }
            AssertUtil.assertNotEmpty(excelResult, "不存在匹配数据请检验，请检查后导入");
            long barCodeCount = excelResult.stream().map(DiseaseResult::getBarCode).distinct().count();
            AssertUtil.assertTrue(excelResult.size() == barCodeCount, "Excel表中存在错误条码数据，请检查后导入");

            // 写入检验结果
            for (DiseaseResult diseaseResult : excelResult) {
                SamplingRecord samplingRecord = samplingRecordMapper.getOne(inspectionId, diseaseResult.getBarCode());
                AssertUtil.assertNotNull(samplingRecord, String.format("Excel表中存在错误条码数据，请检查后导入", diseaseResult.getBarCode()));
                AssertUtil.assertTrue(samplingRecord.getCheckType() != 2, "excel表中存在耐药性检测条码，请检查后导入");
                AssertUtil.assertFalse(samplingRecord.getDiseaseLoad(), String.format("Excel表中存在已导入的条码数据，请检查后导入", diseaseResult.getBarCode()));
                //判断当前采样记录是否已经存在病载数据
                Integer countResult = samplingRecordResultMapper.countDiseaseResult(samplingRecord.getId());
                AssertUtil.assertTrue(countResult == 0, "已存在病载结果数据，请检查后导入");

                Integer diseaseNum = null;
                try {
                    String[] copies = diseaseResult.getResult().split("Copies");
                    if (copies != null && copies.length > 0) {
                        diseaseNum = Integer.parseInt(StringUtils.trim(copies[0]).replaceAll(",", ""));
                    }
                } catch (Exception ex) {
                    log.error("转换病载含量数据异常");
                    throw new BusinessException(ErrorCode.PARAM_ERROR, String.format("病载含数据非法 %s，请检查后导入", diseaseResult.getResult()));
                }

                SamplingRecordResult samplingRecordResult = SamplingRecordResult.builder()
                        .samplingId(samplingRecord.getId())
                        .diseaseResult(diseaseResult.getResult())
                        .diseaseNum(diseaseNum)
                        .build();
                samplingRecordResultMapper.insert(samplingRecordResult);

                //更新采集数据信息，标记病载数据已上传
                samplingRecord.setDiseaseLoad(true);
                if (samplingRecord.getCheckType() == 1) {
                    samplingRecord.setSampleStatus(6);
                } else if (samplingRecord.getCheckType() == 3) {
                    if (samplingRecord.getDrugResistance()) {
                        //已经上传过病载检验数据
                        samplingRecord.setSampleStatus(6);
                    } else {
                        samplingRecord.setSampleStatus(7);
                    }
                }
                samplingRecordMapper.update(samplingRecord);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException(ErrorCode.PARAM_ERROR, "Excel表中存在错误条码数据，请检查后导入");
        }
        return true;
    }

    private boolean checkDrugCode(String drugCode, SamplingRecord samplingRecord) {
        if (drugCode.startsWith(">")) {
            drugCode = drugCode.substring(1);
        }
        if (Objects.equals(drugCode, samplingRecord.getBarCode())) {
            return true;
        }

        return false;
    }

    /**
     * 上传耐药检验结果txt
     *
     * @param file
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean uploadTxtAndResolving(MultipartFile file, Long id) {
        SamplingRecord samplingRecord = samplingRecordMapper.selectById(id);
        AssertUtil.assertNotNull(samplingRecord, "数据不存在");
        try {
            //查询第三方接口数据
            File file1 = FileUtils.multipartFileToFile(file);
            List<String> list = FileUtil.readLines(file1, CharsetUtil.CHARSET_UTF_8);
            //检测当前耐药编号与检测编号是否匹配
            AssertUtil.assertTrue(checkDrugCode(list.get(0), samplingRecord), "当前耐药编号与检测编号不匹配");

            NaiYaoRequest request = NaiYaoRequest.getRequest(list);
            String post = HttpUtil.post(URL, JSON.toJSONString(request));
            AssertUtil.assertTrue(JSONUtil.isJson(post), "查询耐药检测结果失败，请检查文件内容是否正确");
            List<JSONObject> sequenceAnalysis = (List<JSONObject>) JSONUtil.getByPath(JSONUtil.parse(post), "data.sequenceAnalysis");

            //耐药数据
            List<SamplingRecordResult> recordResults = naiYaoResult(id, sequenceAnalysis);
            samplingRecordResultMapper.batchInsert(recordResults);
            List<SamplingRecordResult> pointResults = naiYaoPointResult(id, sequenceAnalysis);
            samplingRecordResultMapper.batchInsert(pointResults);

            samplingRecord.setDrugResistance(true);
            if (samplingRecord.getCheckType() == 2) {
                samplingRecord.setSampleStatus(6);
            } else if (samplingRecord.getCheckType() == 3) {
                if (samplingRecord.getDiseaseLoad()) {
                    //已经上传过耐药检验数据
                    samplingRecord.setSampleStatus(6);
                } else {
                    samplingRecord.setSampleStatus(7);
                }
            }
            samplingRecordMapper.update(samplingRecord);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    private List<SamplingRecordResult> naiYaoResult(Long id, List<JSONObject> sequenceAnalysis) {
        List<SamplingRecordResult> resultList = Lists.newArrayList();
        for (JSONObject analysis : sequenceAnalysis) {
            JSONArray drugResistance = analysis.getJSONArray("drugResistance");
            for (Object o : drugResistance) {
                List<JSONObject> geneDrugClassesList = (List<JSONObject>) JSONUtil.getByPath(JSONUtil.parse(JSON.toJSONString(o)), "gene.drugClasses");
                Map<String, String> map = geneDrugClassesList.stream().collect(Collectors.toMap(key -> key.getStr("name"), value -> value.getStr("fullName")));
                List<JSONObject> levels = JSONUtil.parse(JSON.toJSONString(o)).getByPath("levels", List.class);
                Map<Object, List<JSONObject>> dataMap = levels.stream().collect(Collectors.groupingBy(item -> item.getByPath("drugClass.name")));

                map.forEach((key, value) -> {
                    List<JSONObject> jsonObjects = dataMap.get(key);
                    if (CollectionUtils.isNotEmpty(jsonObjects)) {
                        for (JSONObject jsonObject : jsonObjects) {
                            String drugName = jsonObject.getByPath("drug.fullName").toString();
                            SamplingRecordResult result = SamplingRecordResult.builder().samplingId(id).drugCategory(value).drugName(drugName).type(1).drugResult(jsonObject.getStr("text")).build();
                            resultList.add(result);
                        }
                    }
                });
            }
        }
        return resultList;
    }

    private List<SamplingRecordResult> naiYaoPointResult(Long id, List<JSONObject> sequenceAnalysis) {
        List<SamplingRecordResult> resultList = Lists.newArrayList();
        //1.蛋白酶主要耐药位点
        List<JSONObject> pr_major = getTool(sequenceAnalysis, "蛋白酶区", "主要");
        SamplingRecordResult pr_major_result = buildResult("蛋白酶主要耐药位点", pr_major);
        pr_major_result.setSamplingId(id);
        resultList.add(pr_major_result);
        //2.核苷类似物突变位点
        List<JSONObject> rt_nrti = getTool(sequenceAnalysis, "逆转录酶区", "NRTI相关");
        SamplingRecordResult rt_nrti_result = buildResult("核苷类似物突变位点", rt_nrti);
        rt_nrti_result.setSamplingId(id);
        resultList.add(rt_nrti_result);
        //3.非核苷类似物突变位点
        List<JSONObject> rt_nnrti = getTool(sequenceAnalysis, "逆转录酶区", "NNRTI相关");
        SamplingRecordResult rt_nnrti_result = buildResult("非核苷类似物突变位点", rt_nnrti);
        rt_nnrti_result.setSamplingId(id);
        resultList.add(rt_nnrti_result);
        //4.整合酶主要耐药位点
        List<JSONObject> in_major = getTool(sequenceAnalysis, "整合酶区", "主要");
        SamplingRecordResult in_major_result = buildResult("整合酶主要耐药位点", in_major);
        in_major_result.setSamplingId(id);
        resultList.add(in_major_result);
        return resultList;
    }

    /**
     * 组装耐药点位数据
     * @param drugCategory
     * @param dataList
     * @return
     */
    private SamplingRecordResult buildResult(String drugCategory, List<JSONObject> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return SamplingRecordResult.builder().drugCategory(drugCategory).drugResult("无").type(2).build();
        }

        String drugResult = dataList.stream().map(item -> item.getStr("text")).collect(Collectors.joining("·"));
        return SamplingRecordResult.builder().drugCategory(drugCategory).drugResult(drugResult).type(2).build();
    }

    private List<JSONObject> getTool(List<JSONObject> sequenceAnalysis, String geneName, String mutationType) {
        List<JSONObject> result = Lists.newArrayList();
        for (JSONObject analysis : sequenceAnalysis) {
            JSONArray drugResistance = analysis.getJSONArray("drugResistance");
            for (Object o : drugResistance) {
                //名字匹配
                cn.hutool.json.JSON objJSON = JSONUtil.parse(JSON.toJSONString(o));
                String geneNameTemp = JSONUtil.getByPath(objJSON, "gene.name", null);
                if (Objects.equals(geneNameTemp, geneName)) {
                    //类型匹配
                    List<JSONObject> mutationsByTypes = (List<JSONObject>)JSONUtil.getByPath(objJSON, "mutationsByTypes");
                    for (JSONObject mutationsByTypeObject : mutationsByTypes) {
                        String mutationTypeTemp = mutationsByTypeObject.getStr("mutationType");
                        if (Objects.equals(mutationTypeTemp, mutationType)) {
                            List<JSONObject> mutations1 = JSON.parseArray(JSON.toJSONString(mutationsByTypeObject.getJSONArray("mutations")), JSONObject.class);
                            result.addAll(mutations1);
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 更新报告地址
     *
     * @param record
     * @return
     */
    public Boolean updateReportUrl(SamplingRecord record) {
        SamplingRecord samplingRecord = samplingRecordMapper.selectById(record.getId());
        AssertUtil.assertNotNull(samplingRecord, "数据不存在");
        samplingRecord.setDiseasePdf(record.getDiseasePdf());
        samplingRecord.setDrugPdf(record.getDrugPdf());
        samplingRecordMapper.update(samplingRecord);
        return true;
    }

    /**
     * 上传报告
     *
     * @param request
     * @param file
     * @return
     */
    public String uploadReportPdf(HttpServletRequest request, MultipartFile file) {
        String id = request.getParameter("id");
        AssertUtil.assertNotNull(id, "数据不存在");
        AssertUtil.assertTrue(NumberUtil.isNumber(id), "非法的数据id");
        String type = request.getParameter("type");
        AssertUtil.assertNotNull(type, "报告类型不存在");
        SamplingRecord samplingRecord = samplingRecordMapper.selectById(Long.parseLong(id));
        AssertUtil.assertNotNull(samplingRecord, "数据不存在");
        try {
            String reportUrl = FileUploadUtils.upload("/pdf", file);
            if ("1".equals(type)) {
                samplingRecord.setDiseasePdf(reportUrl);
                samplingRecordMapper.update(samplingRecord);
            } else if ("2".equals(type)) {
                samplingRecord.setDrugPdf(reportUrl);
                samplingRecordMapper.update(samplingRecord);
            }
            return reportUrl;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据盒子编码查询盒子里包含的采样数据
     * @param boxCode
     * @return
     */
    public List<SamplingRecord> listSamplingByBoxCode(String boxCode) {
        List<SamplingRecord> list = samplingRecordMapper.listSamplingByBoxCode(boxCode);
        list.stream().forEach(item -> {
            buildInfo(item);
            item.setBoxCode(boxCode);
        });
        return list;
    }

    /**
     * 根据快递编号查询快递里包含的采样数据
     * @param expressCode
     * @return
     */
    public List<SamplingRecord> listSamplingByExpressCode(String expressCode) {
        List<SamplingRecord> list = samplingRecordMapper.listSamplingByExpressCode(expressCode);
        list.stream().forEach(item -> {
            buildInfo(item);
//            item.setBoxCode(boxCode);
        });
        return list;
    }
}
